package com.moxi.mogublog.redis.service.impl;

import com.moxi.mogublog.redis.service.IRedisService;
import com.moxi.mogublog.redis.utils.DataTypeConvert;
import com.moxi.mogublog.redis.vo.RedisInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.TimeoutUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.*;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Jedis：是Redis官方推荐的Java连接开发工具
 *
 * @author JackLi
 * @version 1.0.0
 * @date 2020/5/31 7:40
 */
@Service
public class RedisServiceImpl implements IRedisService {

    @Autowired
    private JedisPool jedisPool;

    /**
     * 换行符
     */
    private static String separator = System.getProperty("line.separator");

    private String colon = ":";
    private String redisDbSize = "RedisDBSize";
    private String usedMemory = "used_memory";

//    private Jedis jedis = jedisPool.getResource();

    @Override
    public List<RedisInfoVO> getRedisInfo() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            Client client = jedis.getClient();
            client.info();
            String info = client.getBulkReply();
            List<RedisInfoVO> redisInfoVOList = new ArrayList<>();
            String[] strings = Objects.requireNonNull(info).split(separator);
            RedisInfoVO redisInfoVO;
            if (strings.length > 0) {
                for (String str : strings) {
                    redisInfoVO = new RedisInfoVO();
                    String[] strArr = str.split(colon);
                    if (strArr.length > 1) {
                        String key = strArr[0];
                        String value = strArr[1];
                        redisInfoVO.setKey(key);
                        redisInfoVO.setValue(value);
                        redisInfoVOList.add(redisInfoVO);
                    }
                }
            }
            return redisInfoVOList;
        } finally {
            returnResourceToPool(jedis);
        }
    }

    @Override
    public <T> Object eval(String script, List<String> keys, List<String> args) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            Object obj = jedis.eval(script, keys, args);
            return obj;
        } finally {
            returnResourceToPool(jedis);
        }
    }

    @Override
    public <T> String ping() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.ping();
        } finally {
            returnResourceToPool(jedis);
        }
    }

    @Override
    public Map<String, Object> getKeysSize() {
        Jedis jedis = null;
        try {
            Map<String, Object> map = new HashMap<>(1);
            jedis = jedisPool.getResource();
            Client client = jedis.getClient();
            client.dbSize();
            map.put(redisDbSize, client.getIntegerReply());
            return map;
        } finally {
            returnResourceToPool(jedis);
        }
    }

    @Override
    public Map<String, Object> getMemoryInfo() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            Client client = jedis.getClient();
            client.info();
            String memoryInfo = client.getBulkReply();
            String[] strArray = Objects.requireNonNull(memoryInfo).split(separator);
            Map<String, Object> map = null;
            for (String str : strArray) {
                String[] detail = str.split(colon);
                if (usedMemory.equals(detail[0])) {
                    map = new HashMap<String, Object>(1);
                    map.put(usedMemory, detail[1].substring(0, detail[1].length() - 1));
                    break;
                }
            }
            return map;
        } finally {
            returnResourceToPool(jedis);
        }
    }

    @Override
    public Set<String> getKeys(String pattern) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.keys(pattern);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    @Override
    public <T> String flushDB() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.flushDB();
        } finally {
            returnResourceToPool(jedis);
        }
    }

    @Override
    public <T> String flushAll() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.flushAll();
        } finally {
            returnResourceToPool(jedis);
        }
    }


    @Override
    public <T> Long pttl(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.pttl(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    @Override
    public <T> Long expire(String key, Integer seconds) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.expire(key, seconds);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    @Override
    public <T> Long pExpire(String key, Long milliSeconds) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.pexpire(key, milliSeconds);
        } finally {
            returnResourceToPool(jedis);
        }
    }


    /** -------------------key相关操作--------------------- */

    /**
     * 删除key
     */
    @Override
    public <T> boolean delete(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            long ret = jedis.del(key);
            return ret > 0;
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 批量删除key
     */
    @Override
    public <T> Long delete(Collection<String> keys) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.del(keys.toArray(new String[keys.size()]));
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 序列化key
     *
     * @param key
     * @return
     */
    @Override
    public <T> byte[] dump(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.dump(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 是否存在key
     */
    @Override
    public <T> Boolean exists(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.exists(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 设置过期时间
     */
    @Override
    public <T> Long expire(String key, long timeoutSecond) {
        long millis = TimeoutUtils.toMillis(timeoutSecond, TimeUnit.SECONDS);
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.pexpire(key, millis);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 设置过期时间 [以 UNIX 时间戳(unix timestamp)格式]
     */
    @Override
    public <T> Long expireAt(String key, Date date) {
        long unixTime = date.getTime();
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.pexpireAt(key, unixTime);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 查找匹配的key
     */
    @Override
    public <T> Set<String> keys(String pattern) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.keys(pattern);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 将当前数据库的 key 移动到给定的数据库 db 当中
     */
    @Override
    public <T> Long move(String key, int dbIndex) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.move(key, dbIndex);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 移除 key 的过期时间，key 将持久保持
     */
    @Override
    public <T> Long persist(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.persist(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 返回 key 的剩余的过期时间，单位：秒
     */
    @Override
    public <T> Long getExpire(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.ttl(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 从当前数据库中随机返回一个 key
     */
    @Override
    public <T> String randomKey() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.randomKey();
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 修改 key 的名称
     */
    @Override
    public <T> String rename(String oldKey, String newKey) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.rename(oldKey, newKey);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 仅当 newKey 不存在时，将 oldKey 改名为 newKey
     */
    @Override
    public <T> Long renameIfAbsent(String oldKey, String newKey) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.renamenx(oldKey, newKey);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 返回 key 所储存的值的类型
     *
     * @param key
     * @return
     */
    @Override
    public <T> String type(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.type(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /** -------------------Redis数据类型1:字符串（String）：单值单value [start]--------------------- */

    /**
     * 设置指定 key 的值
     */
    @Override
    public <T> String set(String key, T value) {
        return this.setEx(key, value, 0);
    }

    /**
     * 获取指定 key 的值
     */
    @Override
    public String get(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.get(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 返回 key 中字符串值的子字符
     */
    @Override
    public String getRange(String key, long start, long end) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.getrange(key, start, end);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 将给定 key 的值设为 value ，并返回 key 的旧值(old value)
     */
    @Override
    public String getAndSet(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.getSet(key, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 对 key 所储存的字符串值，获取指定偏移量上的位(bit)
     */
    @Override
    public Boolean getBit(String key, long offset) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.getbit(key, offset);
        } finally {
            returnResourceToPool(jedis);
        }

    }

    /**
     * 批量获取
     */
    @Override
    public List<String> multiGet(Collection<String> keys) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.mget(keys.toArray(new String[keys.size()]));
        } finally {
            returnResourceToPool(jedis);
        }
    }

    @Override
    public boolean setBit(String key, long offset, boolean value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.setbit(key, offset, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value
     */
    @Override
    public <T> String setEx(String key, T value, int timeoutSeconds) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String str = DataTypeConvert.beanToString(value);
            if (str == null || str.length() <= 0) {
                return null;
            }
            String result;
            if (timeoutSeconds <= 0) {
                result = jedis.set(key, str);
            } else {
                result = jedis.setex(key, timeoutSeconds, str);
            }
            return result;
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 只有在 key 不存在时设置 key 的值
     */
    @Override
    public Long setIfAbsent(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.setnx(key, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 用 value 参数覆写给定 key 所储存的字符串值，从偏移量 offset 开始
     */
    @Override
    public Long setRange(String key, String value, long offset) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.setrange(key, offset, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取字符串的长度
     */
    @Override
    public Long size(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.strlen(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 批量添加
     *
     * @param maps
     */
//    public void multiSet(Map<String, String> maps) {
//        redisTemplate.opsForValue().multiSet(maps);
//    }

    /**
     * 同时设置一个或多个 key-value 对，当且仅当所有给定 key 都不存在
     *
     * @return 之前已经存在返回false, 不存在返回true
     */
//    public boolean multiSetIfAbsent(Map<String, String> maps) {
//        return redisTemplate.opsForValue().multiSetIfAbsent(maps);
//    }

    /**
     * 增加(自增长), 负数则为自减
     */
    @Override
    public <T> Long incrBy(String key, long increment) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.incrBy(key, increment);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 追加到末尾
     */
    @Override
    public <T> Long append(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.append(key, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }


    /** -------------------Redis数据类型1:字符串（String）：单值单value [end]------------------------- */

    /**
     * -------------------Redis数据类型2:哈希（Hash）：KV模式不变，但V是一个键值对 [start]-------------------------
     */

    /**
     * 获取存储在哈希表中指定字段的值
     */
    @Override
    public <T> T hGet(String key, String field, Class<T> clazz) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String hGet = jedis.hget(key, field);
            return DataTypeConvert.stringToBean(hGet, clazz);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取所有给定字段的值
     */
    @Override
    public <T> Map<String, String> hGetAll(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hgetAll(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取所有给定字段的值
     *
     * @param key
     * @param fields
     * @return
     */
//    public List<Object> hMultiGet(String key, Collection<Object> fields) {
//        return redisTemplate.opsForHash().multiGet(key, fields);
//    }

    /**
     * 获取所有给定字段的值
     */
    @Override
    public Long hPut(String key, String hashKey, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hset(key, hashKey, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

//    public void hPutAll(String key, Map<String, String> maps) {
//        redisTemplate.opsForHash().putAll(key, maps);
//    }

    /**
     * 仅当hashKey不存在时才设置
     */
    @Override
    public Long hPutIfAbsent(String key, String hashKey, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hsetnx(key, hashKey, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 删除一个或多个哈希表字段
     */
    @Override
    public Long hDelete(String key, String... fields) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hdel(key, fields);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 查看哈希表 key 中，指定的字段是否存在
     */
    @Override
    public Boolean hExists(String key, String field) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hexists(key, field);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     */
    @Override
    public Long hIncrBy(String key, String field, long increment) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hincrBy(key, field, increment);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     */
    @Override
    public Double hIncrByFloat(String key, String field, double delta) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hincrByFloat(key, field, delta);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取所有哈希表中的字段
     */
    @Override
    public Set<String> hKeys(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hkeys(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取哈希表中字段的数量
     */
    @Override
    public Long hSize(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hlen(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取哈希表中所有值
     */
    @Override
    public List<String> hValues(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.hvals(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 迭代哈希表中的键值对
     *
     * @param key
     * @param options
     * @return
     */
//    public Cursor<Map.Entry<Object, Object>> hScan(String key, ScanOptions options) {
//        return redisTemplate.opsForHash().scan(key, options);
//    }


    /**
     * 通过索引获取列表中的元素
     */
    @Override
    public String lIndex(String key, long index) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.lindex(key, index);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取列表指定范围内的元素
     */
    @Override
    public List<String> lRange(String key, long start, long end) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.lrange(key, start, end);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 存储在list头部
     */
    @Override
    public <T> Long lLeftPush(String key, T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            // 生成真正的key
            return jedis.lpush(key, DataTypeConvert.beanToString(value));
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * lLeftPushAll-将多个值 value 插入到列表 (key) 的表头,即从list左侧插入
     */
    @Override
    public Long lLeftPushAll(String key, String... value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.lpush(key, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 将多个值 value 插入到列表 (key) 的表头,即从list左侧插入
     */
    @Override
    public <T> Long lLeftPushAll(String key, Collection<T> values) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.lpush(key, values.toArray(new String[values.size()]));
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 当list存在的时候才加入
     */
    @Override
    public <T> Long lLeftPushIfPresent(String key, T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.lpushx(key, DataTypeConvert.beanToString(value));
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 如果pivot存在,再pivot前面添加
     *
     * @param key
     * @param pivot
     * @param value
     * @return
     */
    @Override
    public Long lLeftPush(String key, String pivot, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.linsert(key, ListPosition.BEFORE, pivot, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 将一个值 value 插入到列表 (key) 的表尾,即从list右侧插入
     */
    @Override
    public <T> Long lRightPush(String key, T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.rpush(key, DataTypeConvert.beanToString(value));
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 将多个值 value 插入到列表 (key) 的表尾,即从list右侧插入
     */
    @Override
    public Long lRightPushAll(String key, String... value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.rpush(key, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 将多个值 value 插入到列表 (key) 的表尾,即从list右侧插入
     */
    @Override
    public Long lRightPushAll(String key, Collection<String> value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.rpush(key, value.toArray(new String[value.size()]));
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 为已存在的列表添加值
     */
    @Override
    public <T> Long lRightPushIfPresent(String key, T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.rpushx(key, DataTypeConvert.beanToString(value));
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 在pivot元素的右边添加值
     */
    @Override
    public Long lRightPush(String key, String pivot, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.linsert(key, ListPosition.AFTER, pivot, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 通过索引设置列表元素的值
     *
     * @param key
     * @param index 位置
     * @param value
     */
    @Override
    public <T> String lSet(String key, long index, T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.lset(key, index, DataTypeConvert.beanToString(value));
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 移出并获取列表的第一个元素
     */
    @Override
    public String lLeftPop(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.lpop(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 移出并获取列表的第一个元素， 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     */
    @Override
    public String lBLeftPop(String key, long timeoutSeconds) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            List<String> lPop = jedis.blpop((int) timeoutSeconds, key);
            return CollectionUtils.isEmpty(lPop) ? null : lPop.get(1);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 移除并获取列表最后一个元素
     */
    @Override
    public String lRightPop(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.rpop(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 移出并获取列表的最后一个元素， 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param key
     * @param timeoutSeconds 等待时间，单位：秒
     * @return
     */
    @Override
    public String lBRightPop(String key, long timeoutSeconds) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            List<String> lPop = jedis.brpop((int) timeoutSeconds, key);
            return CollectionUtils.isEmpty(lPop) ? null : lPop.get(1);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 移除列表的最后一个元素，并将该元素添加到另一个列表并返回
     *
     * @param sourceKey
     * @param destinationKey
     * @return
     */
    @Override
    public String lRightPopAndLeftPush(String sourceKey, String destinationKey) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.rpoplpush(sourceKey, destinationKey);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 从列表中弹出一个值，将弹出的元素插入到另外一个列表中并返回它； 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param sourceKey
     * @param destinationKey
     * @param timeoutSeconds 超时时间，单位：秒
     * @return
     */
    @Override
    public String lBRightPopAndLeftPush(String sourceKey, String destinationKey, long timeoutSeconds) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.brpoplpush(sourceKey, destinationKey, (int) timeoutSeconds);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 删除集合中值等于 value 的元素
     *
     * @param key
     * @param index index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素;
     *              index<0, 从尾部开始删除第一个值等于value的元素;
     * @param value
     * @return
     */
    @Override
    public Long lRemove(String key, long index, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.lrem(key, index, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 裁剪list
     */
    @Override
    public String lTrim(String key, long start, long end) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.ltrim(key, start, end);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取列表长度
     */
    @Override
    public Long lLen(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.llen(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }


    /** --------------------set相关操作-------------------------- */

    /**
     * set添加元素
     */
    @Override
    public <T> Long sAdd(String key, String... values) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.sadd(key, values);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * set移除元素
     */
    @Override
    public Long sRemove(String key, String... values) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.srem(key, values);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 移除并返回集合的一个随机元素
     */
    @Override
    public String sPop(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.spop(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 将元素value从一个集合移到另一个集合
     */
    @Override
    public Long sMove(String key, String value, String destKey) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.smove(key, value, destKey);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取集合的大小
     *
     * @param key
     * @return
     */
    @Override
    public Long sSize(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.scard(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 判断集合是否包含value
     */
    @Override
    public Boolean sIsMember(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.sismember(key, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取两个集合的交集
     */
    @Override
    public Set<String> sIntersect(String key, String otherKey) {
//        List<String> strings = Arrays.asList(key, otherKey);
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.sinter(key, otherKey);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取key集合与多个集合的交集
     */
    @Override
    public Set<String> sIntersect(String key, Collection<String> otherKeys) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String[] strings = new String[otherKeys.size() + 1];
            otherKeys.toArray(strings);
            strings[otherKeys.size() + 1] = key;
            return jedis.sinter(strings);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * key集合与otherKey集合的交集存储到destKey集合中
     */
    @Override
    public Long sIntersectAndStore(String key, String otherKey, String destKey) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.sinterstore(destKey, key, otherKey);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * key集合与多个集合的交集存储到destKey集合中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
//    public Long sIntersectAndStore(String key, Collection<String> otherKeys, String destKey) {
//        return redisTemplate.opsForSet().intersectAndStore(key, otherKeys, destKey);
//    }

    /**
     * 获取两个集合的并集
     */
    @Override
    public Set<String> sUnion(String key, String otherKeys) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.sunion(key, otherKeys);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取key集合与多个集合的并集
     *
     * @param key
     * @param otherKeys
     * @return
     */
//    public Set<String> sUnion(String key, Collection<String> otherKeys) {
//        return redisTemplate.opsForSet().union(key, otherKeys);
//    }

    /**
     * key集合与otherKey集合的并集存储到destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
//    public Long sUnionAndStore(String key, String otherKey, String destKey) {
//        return redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey);
//    }

    /**
     * key集合与多个集合的并集存储到destKey中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
//    public Long sUnionAndStore(String key, Collection<String> otherKeys, String destKey) {
//        return redisTemplate.opsForSet().unionAndStore(key, otherKeys, destKey);
//    }

    /**
     * 获取两个集合的差集
     */
    @Override
    public Set<String> sDifference(String key, String otherKey) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.sdiff(key, otherKey);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取key集合与多个集合的差集
     *
     * @param key
     * @param otherKeys
     * @return
     */
//    public Set<String> sDifference(String key, Collection<String> otherKeys) {
//        return redisTemplate.opsForSet().difference(key, otherKeys);
//    }

    /**
     * key集合与otherKey集合的差集存储到destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
//    public Long sDifference(String key, String otherKey, String destKey) {
//        return redisTemplate.opsForSet().differenceAndStore(key, otherKey, destKey);
//    }

    /**
     * key集合与多个集合的差集存储到destKey中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
//    public Long sDifference(String key, Collection<String> otherKeys, String destKey) {
//        return redisTemplate.opsForSet().differenceAndStore(key, otherKeys, destKey);
//    }

    /**
     * 获取集合所有元素
     */
    @Override
    public Set<String> getSetMembers(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.smembers(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 随机获取集合中的一个元素
     */
    @Override
    public String sRandomMember(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.srandmember(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 随机获取集合中count个元素
     */
    @Override
    public List<String> sRandomMembers(String key, int count) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.srandmember(key, count);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 随机获取集合中count个元素并且去除重复的
     */
    @Override
    public Set<String> sDistinctRandomMembers(String key, int count) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return new HashSet(jedis.srandmember(key, count));
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * @param key
     * @param options
     * @return
     */
//    public Cursor<String> sScan(String key, ScanOptions options) {
//        return redisTemplate.opsForSet().scan(key, options);
//    }


    /**
     * 添加元素,有序集合是按照元素的score值由小到大排列
     */
    @Override
    public Long zAdd(String key, String value, double score) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zadd(key, score, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * @param key
     * @param values
     * @return
     */
//    public Long zAdd(String key, Set<ZSetOperations.TypedTuple<String>> values) {
//        return redisTemplate.opsForZSet().add(key, values);
//    }

    /**
     * @param key
     * @param values
     * @return
     */
    @Override
    public Long zRemove(String key, String... values) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrem(key, values);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 增加元素的score值，并返回增加后的值
     *
     * @param key
     * @param value
     * @param delta
     * @return
     */
    @Override
    public Double zIncrementScore(String key, String value, double delta) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zincrby(key, delta, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
     *
     * @param key
     * @param value
     * @return 0表示第一位
     */
    @Override
    public Long zRank(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrank(key, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 返回元素在集合的排名,按元素的score值由大到小排列
     */
    @Override
    public Long zReverseRank(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrevrank(key, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取集合的元素, 从小到大排序
     */
    @Override
    public Set<String> zRange(String key, long start, long end) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrange(key, start, end);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取集合元素, 并且把score值也获取
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    @Override
    public Set<Tuple> zRangeWithScores(String key, long start, long end) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrangeWithScores(key, start, end);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 根据Score值查询集合元素
     */
    @Override
    public Set<String> zRangeByScore(String key, double min, double max) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrangeByScore(key, min, max);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 根据Score值查询集合元素, 从小到大排序
     */
    @Override
    public Set<Tuple> zRangeByScoreWithScores(String key, double min, double max) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrangeByScoreWithScores(key, min, max);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * @param key
     * @param min
     * @param max
     * @param start
     * @param end
     * @return
     */
    @Override
    public Set<Tuple> zRangeByScoreWithScores(String key, double min, double max, int start, int end) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrangeByScoreWithScores(key, min, max, start, end);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取集合的元素, 从大到小排序
     */
    @Override
    public Set<String> zReverseRange(String key, long start, long end) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrevrange(key, start, end);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取集合的元素, 从大到小排序, 并返回score值
     */
    @Override
    public Set<Tuple> zReverseRangeWithScores(String key, long start, long end) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrevrangeWithScores(key, start, end);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 根据Score值查询集合元素, 从大到小排序
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    @Override
    public Set<String> zReverseRangeByScore(String key, double min, double max) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrevrangeByScore(key, min, max);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 根据Score值查询集合元素, 从大到小排序
     */
    @Override
    public Set<Tuple> zReverseRangeByScoreWithScores(String key, double min, double max) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrevrangeByScoreWithScores(key, min, max);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * @param key
     * @param min
     * @param max
     * @param start
     * @param end
     * @return
     */
    @Override
    public Set<String> zReverseRangeByScore(String key, double min, double max, int start, int end) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zrevrangeByScore(key, min, max, start, end);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 根据score值获取集合元素数量
     */
    @Override
    public Long zCount(String key, double min, double max) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zcount(key, min, max);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取集合大小
     */
    @Override
    public Long zSize(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zcard(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取集合大小
     */
    @Override
    public Long zZCard(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zcard(key);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取集合中value元素的score值
     */
    @Override
    public Double zScore(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zscore(key, value);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 移除指定索引位置的成员
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    @Override
    public Long zRemoveRange(String key, long start, long end) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zremrangeByRank(key, start, end);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 根据指定的score值的范围来移除成员
     */
    @Override
    public Long zRemoveRangeByScore(String key, double min, double max) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.zremrangeByScore(key, min, max);
        } finally {
            returnResourceToPool(jedis);
        }
    }

    /**
     * 获取key和otherKey的并集并存储在destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
//    public Long zUnionAndStore(String key, String otherKey, String destKey) {
//        return redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey);
//    }

    /**
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
//    public Long zUnionAndStore(String key, Collection<String> otherKeys, String destKey) {
//        return redisTemplate.opsForZSet().unionAndStore(key, otherKeys, destKey);
//    }

    /**
     * 交集
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
//    public Long zIntersectAndStore(String key, String otherKey, String destKey) {
//        return redisTemplate.opsForZSet().intersectAndStore(key, otherKey, destKey);
//    }

    /**
     * 交集
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
//    public Long zIntersectAndStore(String key, Collection<String> otherKeys, String destKey) {
//        return redisTemplate.opsForZSet().intersectAndStore(key, otherKeys, destKey);
//    }

    /**
     * @param key
     * @param options
     * @return
     */
//    public Cursor<ZSetOperations.TypedTuple<String>> zScan(String key, ScanOptions options) {
////        return redisTemplate.opsForZSet().scan(key, options);
////    }

    /**
     * 获取Redis List 序列化
     *
     * @param key
     * @param targetClass
     * @param <T>
     * @return
     */
//    public <T> List<T> getListCache(final String key, Class<T> targetClass) {
//        byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
//            @Override
//            public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
//                return connection.get(key.getBytes());
//            }
//        });
//        if (result == null) {
//            return null;
//        }
//        return ProtoStuffSerializerUtil.deserializeList(result, targetClass);
//    }

    /***
     * 将List 放进缓存里面
     * @param key
     * @param objList
     * @param expireTime
     * @param <T>
     * @return
     */
//    public <T> boolean putListCacheWithExpireTime(String key, List<T> objList, final long expireTime) {
//        final byte[] bkey = key.getBytes();
//        final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
//        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
//            @Override
//            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
//                connection.setEx(bkey, expireTime, bvalue);
//                return true;
//            }
//        });
//        return result;
//    }


    // ------------------------------ 分界线：私有方法 ---------------------------------------------

    /**
     * 关闭/归还redis连接 [返回资源]
     *
     * @param jedis jedis 形式参数
     */
    private void returnResourceToPool(Jedis jedis) {
        if (jedis != null) {
            // 关闭连接
            jedis.close();
        }
    }

}
